﻿using System.Text.RegularExpressions;

namespace D.UtilRegMatch
{
    /// <summary>
    /// 正则匹配
    /// </summary>
    public static class RegexUtil
    {
        /// <summary>
        ///     正则表达式匹配，匹配返回true
        /// </summary>
        /// <param name="checkString">检查字符串</param>
        /// <param name="regexString">正则表达式字符串</param>
        /// <returns>是否匹配</returns>
        public static bool IsMatch(string checkString, string regexString)
        {
            return IsMatch(checkString, regexString, RegexOptions.IgnoreCase);
        }

        /// <summary>
        ///     正则表达式匹配，匹配返回true
        /// </summary>
        /// <param name="checkString">检查字符串</param>
        /// <param name="regexString">正则表达式字符串</param>
        /// <param name="options">筛选条件</param>
        /// <returns>是否匹配</returns>
        public static bool IsMatch(string checkString, string regexString, RegexOptions options)
        {
            return Regex.IsMatch(checkString, regexString, options);
        }

        /// <summary>
        /// 正则表达式匹配，匹配返回true
        /// </summary>
        /// <param name="checkString">检查字符串</param>
        /// <param name="regexString">模式字符串</param>
        /// <param name="result">若匹配成功，则返回Match</param>
        /// <returns>匹配是否成功</returns>
        public static bool IsMatch(string checkString, string regexString, out Match result)
        {
            result = null;
            var regex = new Regex(regexString);
            result = regex.Match(checkString);
            return result.Success;
        }

        /// <summary>
        /// 是否是Base64
        /// </summary>
        /// <param name="data">验证数据</param>
        /// <returns>是否是Base64</returns>
        public static bool IsBase64(string data)
        {
            return (data.Length % 4) == 0 && IsMatch(data, RegexPattern.Base64Check);
        }

        /// <summary>
        /// 判断是否是BCD字符串
        /// </summary>
        /// <param name="data">验证字符串</param>
        /// <returns>否是BCD字符串</returns>
        public static bool IsBinaryCodedDecimal(string data)
        {
            return IsMatch(data, RegexPattern.BinaryCodedDecimal);
        }

        /// <summary>
        /// 是否是中文
        /// </summary>
        /// <param name="data">验证字符串</param>
        /// <returns>是否是中文</returns>
        public static bool IsChinses(string data)
        {
            return IsMatch(data, RegexPattern.ChineseCheck);
        }

        /// <summary>
        /// 是否是中文或字母
        /// </summary>
        /// <param name="data">验证数据</param>
        /// <returns>是否合法</returns>
        public static bool IsChinsesOrCharacter(string data)
        {
            return IsMatch(data, RegexPattern.ChineseOrCharacterCheck);
        }

        /// <summary>
        /// 是否是日期格式
        /// <para>eg:CheckHelper.IsDate("2014年12月12日");==>true</para>
        /// </summary>
        /// <param name="data">需要判断字符串</param>
        /// <returns>是否是日期格式</returns>
        public static bool IsDate(string data)
        {
            if (string.IsNullOrEmpty(data))
            {
                return false;
            }

            if (IsMatch(data, RegexPattern.DateCheck))
            {
                data = data.Replace("年", "-");
                data = data.Replace("月", "-");
                data = data.Replace("日", " ");
                data = data.Replace("  ", " ");
                return DateTime.TryParse(data, out _);
            }

            return false;
        }

        /// <summary>
        /// 验证是否是email
        /// <para>eg:CheckHelper.IsEmail("Yan.Zhiwei@hotmail.com");==true</para>
        /// </summary>
        /// <param name="data">验证字符串</param>
        /// <returns>是否是email</returns>
        public static bool IsEmail(string data)
        {
            return IsMatch(data, RegexPattern.EmailCheck);
        }

        /// <summary>
        /// 验证是否是文件路径
        /// <para>eg:CheckHelper.IsFilePath(@"C:\alipay\log.txt");==>true</para>
        /// </summary>
        /// <param name="data">验证字符串</param>
        /// <returns>是否是文件路径</returns>
        public static bool IsFilePath(string data)
        {
            return IsMatch(data, RegexPattern.FileCheck);
        }

        /// <summary>
        /// 是否是十六进制字符串
        /// </summary>
        /// <param name="data">验证数据</param>
        /// <returns>是否是十六进制字符串</returns>
        public static bool IsHexString(string data)
        {
            return IsMatch(data, RegexPattern.HexStringCheck);
        }

        /// <summary>
        /// 是否是身份证号码
        /// </summary>
        /// <param name="data">验证数据</param>
        /// <returns>是否是身份证号码</returns>
        public static bool IsIdCard(string data)
        {
            return IsMatch(data, RegexPattern.IdCardCheck);
        }

        /// <summary>
        /// 是否是整数
        /// </summary>
        /// <returns>Validation</returns>
        public static bool IsInt(string data)
        {
            return IsMatch(data, RegexPattern.IntCheck);
        }


        /// <summary>
        /// 是否是内网IP
        /// </summary>
        /// <param name="ipAddress">ip地址</param>
        /// <returns></returns>
        public static bool IsLocalIp4(this string ipAddress)
        {
            /*
             * 知识：
             * Internet设计者保留了IPv4地址空间的一部份供专用地址使用,专用地址空间中的IPv4地址叫专用地址,这些地址永远不会被当做公用地址来分配,所以专用地址永远不会与公用地址重复.
             * IPv4专用地址如下：
             * IP等级 IP位置==>Class A 10.0.0.0-10.255.255.255
             * 默认子网掩码:255.0.0.0==>Class B 172.16.0.0-172.31.255.255
             * 默认子网掩码:255.255.0.0==>Class C 192.168.0.0-192.168.255.255
             * 默认子网掩码:255.255.255.0
             * 内网是可以上网的.内网需要一台服务器或路由器做网关,通过它来上网
             * 做网关的服务器有一个网关（服务器/路由器）的IP地址,其它内网电脑的IP可根据它来随意设置,前提是IP前三个数要跟它一样,第四个可从0-255中任选但要跟服务器的IP不同
             */
            bool result = false;

            if (!string.IsNullOrEmpty(ipAddress) && IsIp4Address(ipAddress))
            {
                result |= (ipAddress.StartsWith("192.168.", StringComparison.OrdinalIgnoreCase) || ipAddress.StartsWith("172.", StringComparison.OrdinalIgnoreCase) || ipAddress.StartsWith("10.", StringComparison.OrdinalIgnoreCase));
            }

            return result;
        }

        /// <summary>
        /// 验证是否是URL
        /// <para>eg:CheckHelper.IsURL("www.cnblogs.com/yan-zhiwei");==>true</para>
        /// </summary>
        /// <param name="data">验证字符串</param>
        /// <returns>是否是URL</returns>
        public static bool IsUrl(string data)
        {
            return IsMatch(data, RegexPattern.UrlCheck);
        }

        /// <summary>
        /// 验证是否是邮政编码
        /// </summary>
        /// <param name="data">验证字符串</param>
        /// <returns>是否是邮政编码</returns>
        public static bool IsPoseCode(string data)
        {
            return IsMatch(data, RegexPattern.PostCodeCheck);
        }


        /// <summary>
        /// 是否是IP
        /// </summary>
        /// <param name="data">需要检测到IP</param>
        /// <returns>Validation</returns>
        public static bool IsIp4Address(string data)
        {
            return IsMatch(data, RegexPattern.IpCheck);
        }

        /// <summary>
        /// 验证MAC地址，支持6或7个长度MAC地址
        /// </summary>
        /// <param name="data">验证对象</param>
        /// <returns>是否是MAC地址</returns>
        public static bool IsMacAddr(string data)
        {
            return IsMatch(data, RegexPattern.MacAddr6Check) || IsMatch(data, RegexPattern.MacAddr7Check);
        }

        /// <summary>
        /// 是否是数字
        /// <para>eg:CheckHelper.IsNumber("abc");==>false</para>
        /// </summary>
        /// <param name="data">判断字符串</param>
        /// <returns>是否是数字</returns>
        public static bool IsNumber(string data)
        {
            return IsMatch(data, RegexPattern.NumberCheck);
        }


        /// <summary>
        /// 对手机号邮箱等隐私信息进行*号打码
        /// </summary>
        /// <param name="s">字符串</param>
        /// <param name="mask">掩码符</param>
        /// Regex.Replace(s, @"(.{3}).*(.{4})", "$1****$2")
        /// <returns></returns>
        public static string Mask(this string s, char mask = '*')
        {
            if (string.IsNullOrWhiteSpace(s?.Trim()))
            {
                return s;
            }
            s = s.Trim();
            string masks = mask.ToString().PadLeft(4, mask);
            return s.Length switch
            {
                >= 11 => Regex.Replace(s, "(.{3}).*(.{4})", $"$1{masks}$2"),
                10 => Regex.Replace(s, "(.{3}).*(.{3})", $"$1{masks}$2"),
                9 => Regex.Replace(s, "(.{2}).*(.{3})", $"$1{masks}$2"),
                8 => Regex.Replace(s, "(.{2}).*(.{2})", $"$1{masks}$2"),
                7 => Regex.Replace(s, "(.{1}).*(.{2})", $"$1{masks}$2"),
                6 => Regex.Replace(s, "(.{1}).*(.{1})", $"$1{masks}$2"),
                _ => Regex.Replace(s, "(.{1}).*", $"$1{masks}")
            };
        }
    }
}
